package visualization;

import graphs.XYInputsvOuputByThetaGraph;

import java.util.ArrayList;


import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;

import odor.Odor;

import java.awt.Dimension;
import java.io.*;

import structures.Network;
import util.Util;

public class NeuroBaldrControlFrame extends JFrame implements RunsSimulation
{
	private ArrayList<JNetwork> networkArray;
	private JTabbedPane networkProcesTabs;
	public static final int X_OFFSET = 105;
	public static final int Y_OFFSET = 55;
	private Odor[] battery;
	private File batteryFile;
	private XYInputsvOuputByThetaGraph outputGraph;
	private File saveDirectory;
	private OptionsFrame optionsFrame;
	private ControlWidget myControlWidget;
	
	private class MainControlFrame extends ControlWidget
	{
		private javax.swing.JButton showOptionsScreen;
		private javax.swing.JButton showSimulationScreen;
		
		public MainControlFrame(RunsSimulation runner ,Odor[] battery)
		{
			super(runner ,battery);
			
			showOptionsScreen = new javax.swing.JButton("Show Options");
			
			showOptionsScreen.addActionListener(new java.awt.event.ActionListener()
			{
				public void actionPerformed(java.awt.event.ActionEvent evt)
				{
					optionsFrame.setVisible(true);
					internalSetVisible(false);
				}
			});
			
			showSimulationScreen = new javax.swing.JButton("Show Simulation");
			
			showSimulationScreen.addActionListener(new java.awt.event.ActionListener()
			{
				public void actionPerformed(java.awt.event.ActionEvent evt)
				{
					optionsFrame.setVisible(false);
					internalSetVisible(true);
					forceTabUpdate();
				}
			});
			
			this.add(showOptionsScreen);
			this.add(showSimulationScreen);
			pack();
		}
	}
	
	@Deprecated
	public NeuroBaldrControlFrame(int numNetworks)
	{
		//STEP 1: Save Location Load/Set
		setupDirectory();
		
		//STEP 1.5: Generate Initial Networks
		networkArray = new ArrayList<JNetwork>(numNetworks);
		for (int x=0; x<numNetworks; x++)
		{
			networkArray.add(new JNetwork(new Network(main.Main.NUM_COLS)));
		}
		
		//STEP 2: Show Options Screen
		optionsFrame = new OptionsFrame(networkArray);
		optionsFrame.setVisible(true);
		
	}
	
	/**
	 * Forces JTab update by removing and replacing all JNetworks
	 */
	private void forceTabUpdate()
	{
		networkProcesTabs.removeAll();
		
		for (JNetwork jn : networkArray)
		{
			networkProcesTabs.addTab(jn.toString(), jn);
		}
		
		networkProcesTabs.validate();
		validate();
	}
	
	@Deprecated
	private void addJNetworkTab(Network n)
	{
		JNetwork temp = new JNetwork(n);
		
		if (!networkArray.contains(temp))
		{	
			networkArray.add(temp);
		}
		
		networkProcesTabs.addTab(temp.toString(), temp);
		networkProcesTabs.validate();
	}
	
	/**
	 * Adds JNetwork to tab iff it's not in there already
	 * @param temp
	 */
	private void addJNetworkTab(JNetwork temp)
	{		
		if (!networkArray.contains(temp))
		{	
			networkArray.add(temp);
		}
		
		networkProcesTabs.addTab(temp.toString(), temp);
		networkProcesTabs.validate();
	}
	
	private void internalSetVisible(boolean s)
	{
		setVisible(s);
	}
	
	public NeuroBaldrControlFrame(int numNetworks, Odor[] battery)
	{
		//STEP 1: Save Location Load/Set
		setupDirectory();
		
		//STEP 1.5: Generate Initial Networks
		networkArray = new ArrayList<JNetwork>(numNetworks);
		for (int x=0; x<numNetworks; x++)
		{
			networkArray.add(new JNetwork(new Network(main.Main.NUM_COLS)));
		}
		
		//STEP 2: Setup Options Screen
		this.battery = battery;
		optionsFrame = new OptionsFrame(networkArray, battery);
		
		//STEP 3: Setup Simulation Screen
		networkProcesTabs = new JTabbedPane(SwingConstants.LEFT);
		
		for (JNetwork j : networkArray)
		{
			addJNetworkTab(j);
		}
		
		//STEP 4: Setup Control Widget
		myControlWidget = new MainControlFrame(this, battery);
		myControlWidget.setVisible(true);
		
		//STEP 5: Display
		setContentPane(networkProcesTabs);
		initializeGraphics();
		validate();
	}
	
	/**
	 * Sets default window properties
	 */
	public void initializeGraphics()
	{
		setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
		this.setSize(new Dimension(X_OFFSET+JNetwork.COL_START_X+JNetwork.COL_OFFSET*networkArray.get(0).getNumCols(), 
				Y_OFFSET+JNetwork.COL_START_Y+JNetwork.GRANULE_RADIUS*JNetwork.getGranulesPerColumn(networkArray.get(0))));
		setTitle("Main Simulation");
	}
	
	private void setupDirectory()
	{
		try
		{
			atttemptDefaultLocationLoad();
		}
		catch(IOException e)
		{
			JOptionPane.showConfirmDialog(this, "Unable to Load Files from Default Directory: Continuing Anyways");
		}
		
		boolean canWork = (saveDirectory != null && saveDirectory.exists() &&saveDirectory.isDirectory() && saveDirectory.list() != null);
		
		while(canWork == false)
		{
			String tempInput = JOptionPane.showInputDialog("Please enter default save location: ");
			
			if (tempInput == null)
			{
				System.exit(0);
			}
			else
			{
				saveDirectory = new File(tempInput);
				saveDirectory.mkdir();
				canWork = (saveDirectory.exists() && saveDirectory.isDirectory() && saveDirectory.canRead() && saveDirectory.canWrite());
			}
			
			if (!canWork)
			{
				JOptionPane.showMessageDialog(this, "Error: Invalid Directory. Try Again");
			}
			
		}
	}
	
	private void atttemptDefaultLocationLoad() throws IOException
	{
		File test;
		if (Util.getOS() == Util.IS_LINUX || Util.getOS() == Util.IS_MAC)
		{
			test = new File(""+System.getProperty("user.home")+File.separatorChar+".neurobaldr");			
		}
		else if (Util.getOS() == Util.IS_WINDOWS)
		{
			test = new File(""+System.getenv("APPDATA")+File.separatorChar+".neurobaldr");
		}
		else
		{
			throw new UnsupportedOperationException();
		}
		
		if (test.exists() && test.isDirectory())
		{
			saveDirectory = test;
			batteryFile = new File(saveDirectory.getAbsolutePath()+File.separatorChar+"odorbattery.dat");
			
			if (batteryFile.exists())
			{
				battery = Odor.fileToBattery(batteryFile);
			}
			else
			{
				batteryFile.createNewFile();
			}
			
		}
		else
		{
			saveDirectory = test;
			saveDirectory.mkdir();
			
			batteryFile = new File(saveDirectory.getAbsolutePath()+File.separatorChar+"odorbattery.dat");
			batteryFile.createNewFile();
		}
	}
	
	//TODO Fix getJNetwork()
	public JNetwork getJNetwork() 
	{
		return null;
	}

	public void runSimulation(Object data)
	{
		boolean flag = false;
		
		for(JNetwork network : networkArray)
		{
			network.fire(myControlWidget.getSelectedOdor());
				
			if (outputGraph == null || flag == false)
			{
				outputGraph = new XYInputsvOuputByThetaGraph(network, myControlWidget.getSelectedOdor());
				flag = true;
			}
			else
			{
				outputGraph.addXYSeries(network);
			}		
		
			outputGraph.setVisible(true);
			
			validate();
			this.repaint();
			
			network.resetGranules();
		}
	}

	public void setOdor(Odor input)
	{
		for(JNetwork network : networkArray)
		{
			network.setOdor(input);
		}
	}

}
